package com.hxkcloud.patient.aerotel.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class DateUtil {
    public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone("GMT");

    public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm";
    public static final String DATETIME_FORMAT_S = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT = "yyyy-MM-dd";
    public static final String TIME_FORMAT = "HH:mm";
    public static final String DATETIME_ISO8601_FORMAT = "yyyyMMdd'T'HH:mm:ss";

    /**
     * milliseconds per second, 1000L
     */
    public static final long MILLIS_OF_SECOND = 1000L;

    /**
     * milliseconds per minute, 60L*1000L
     */
    public static final long MILLIS_OF_MINUTE = 60L * 1000L;

    /**
     * milliseconds per hour, 3600L*1000L=3,600,000L
     */
    public static final long MILLIS_OF_HOUR = 60L * MILLIS_OF_MINUTE;

    /**
     * milliseconds per day, 24L*3600L*1000L
     */
    public static final long MILLIS_OF_DAY = 24L * MILLIS_OF_HOUR;

    /**
     * milliseconds per year, 365L*24L*3600L*1000L;
     */
    public static final long MILLIS_OF_YEAR = 365L * MILLIS_OF_DAY;
    private static final int[] DAYS = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31,
            30, 31};

    /**
     * Get the previous time, from how many days to now.
     *
     * @param days How many days.
     * @return The new previous time.
     */
    public static long daysago(int days) {
        return System.currentTimeMillis() - 3600000L * 24L * days;
    }

    /**
     * Get the next time, from how many days to now.
     *
     * @param days How many days.
     * @return The new next time.
     */
    public static long afterdays(int days) {
        return System.currentTimeMillis() + 3600000L * 24L * days;
    }

    /**
     * get now datetime
     *
     * @return date object for now
     */
    public static Date now() {
        return new Date();
    }

    public static Date now(long millis, TimeZone zone) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(millis);
        cal.setTimeZone(zone);
        return cal.getTime();
    }

    public static Date now(TimeZone zone) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(zone);
        return cal.getTime();
    }

    public static Date nowutc() {
        return now(UTC_TIME_ZONE);
    }

    /**
     * get now datetime
     *
     * @return date object for now
     */
    public static String now(String format) {
        return format(now(), format);
    }

    public static String now(String format, TimeZone zone) {
        return format(now(), format, zone);
    }

    /**
     * format date and time to specified format string
     *
     * @param d date object
     * @param f date format
     * @return date string
     */
    public static String format(Date d, String f) {
        return new SimpleDateFormat(f).format(d);
    }

    public static String format(Date d, String f, TimeZone zone) {
        DateFormat df = new SimpleDateFormat(f);
        df.setTimeZone(zone);
        return df.format(d);
    }

    /**
     * format date to string like "yyyy-MM-dd hh:mm"
     *
     * @param d date object
     * @return date string
     */
    public static String formatDateTime(Date d) {
        return format(d, DATETIME_FORMAT);
    }

    public static String normalize(String date, String fromformat, String format) throws ParseException {
        Date dt = new SimpleDateFormat(fromformat).parse(date);
        return format(dt, format);
    }

    /**
     * Convert date and time to string like "yyyy-MM-dd HH:mm:ss".
     *
     * @param d date object
     * @return date string
     */
    public static String formatDateTimes(Date d) {
        return format(d, DATETIME_FORMAT_S);
    }

    /**
     * Convert time to string like "HH:mm".
     *
     * @param d date object
     */
    public static String formatTime(Date d) {
        return format(d, TIME_FORMAT);
    }

    /**
     * Convert date to String like "yyyy-MM-dd".
     *
     * @param d date object
     */
    public static String formatDate(Date d) {
        return format(d, DATE_FORMAT);
    }

    /**
     * Parse date String to Date Object
     *
     * @param t Date String
     * @param f Date Format
     * @return Date Object
     * @throws ParseException
     */
    public static Date parse(String d, String f) throws ParseException {
        return new SimpleDateFormat(f).parse(d);
    }

    /**
     * Parse date and time like "yyyy-MM-dd hh:mm".
     *
     * @param dt Date String
     * @return Date Object
     * @throws ParseException
     */
    public static Date parse(String dt) throws ParseException {
        return parse(dt, DATETIME_FORMAT);
    }

    public static Date parse(long millis) {
        Calendar cal = Calendar.getInstance();
        cal.setTimeInMillis(millis);
        return cal.getTime();
    }

    /**
     * get today's time with hour offset.
     *
     * @param hourOffset hour offset
     * @return date in millis
     */
    public static long getToday(int hourOffset) {
        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(System.currentTimeMillis());
        c.set(Calendar.HOUR_OF_DAY, hourOffset);
        c.clear(Calendar.MINUTE);
        c.clear(Calendar.SECOND);
        c.clear(Calendar.MILLISECOND);
        return c.getTimeInMillis();
    }

    /**
     * Get Calendar instance by specified year, month and day.
     *
     * @param year  4-digit year, 1900~9999.
     * @param month Month range is 1-12.
     * @param day   Day range is 1-?, end depends on year and month.
     * @return A Calendar instance.
     */
    public static Calendar getCalendar(int year, int month, int day) {
        if (year < 1900 || year > 9999)
            throw new IllegalArgumentException("year");
        if (month < 1 || month > 12)
            throw new IllegalArgumentException("month");
        if (day < 1)
            throw new IllegalArgumentException("day");
        if (month == 2 && isLeapYear(year)) {
            if (day > 29)
                throw new IllegalArgumentException("day");
        } else {
            if (day > DAYS[month - 1])
                throw new IllegalArgumentException("day");
        }
        month--;
        Calendar c = Calendar.getInstance();
        c.set(Calendar.YEAR, year);
        c.set(Calendar.MONTH, month);
        c.set(Calendar.DAY_OF_MONTH, day);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c;
    }

    /**
     * check the year is leap year or not
     *
     * @param year
     * @return boolean true indicates leap year, false not
     */
    public static boolean isLeapYear(int year) {
        if (year % 100 == 0) {
            return year % 400 == 0;
        }
        return year % 4 == 0;
    }

    public static String format(int hour, int minute, String format) {
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, hour);
        c.set(Calendar.MINUTE, minute);
        c.set(Calendar.SECOND, 0);
        return new SimpleDateFormat(format).format(c.getTime());
    }

    public static String format(int year, int month, int day, String format) {
        Calendar c = getCalendar(year, month, day);
        return format(c.getTime(), format);
    }

    public static Date getPrevDay(int year, int month, int day) {
        day--;
        if (day < 1) {
            month--;
            if (month < 1) {
                year--;
                month = 12;
            }
            int lastDay = DAYS[month - 1];
            if (month == 2 && isLeapYear(year))
                lastDay++;
            day = lastDay;
        }
        return getCalendar(year, month, day).getTime();
    }

    public static Date getNextDay(int year, int month, int day) {
        day++;
        int max = DAYS[month - 1];
        if (month == 2 && isLeapYear(year))
            max++;
        if (day > max) {
            day = 1;
            month++;
            if (month > 12) {
                year++;
                month = 1;
            }
        }
        return getCalendar(year, month, day).getTime();
    }

    /**
     * date subtraction
     *
     * @param date1
     * @param date2
     * @param field 1 indicates day 2 indicates hour 3 indicates minute 4
     *              indicates second
     * @return difference in field between date1 and date2
     */
    public static long subtract(Date date1, Date date2, int field) {
        long diff = 0L;
        switch (field) {
            case 1:
                diff = (date1.getTime() - date2.getTime()) / MILLIS_OF_DAY;
                break;
            case 2:
                diff = (date1.getTime() - date2.getTime()) / MILLIS_OF_HOUR;
                break;
            case 3:
                diff = (date1.getTime() - date2.getTime()) / MILLIS_OF_MINUTE;
                break;
            case 4:
                diff = (date1.getTime() - date2.getTime()) / MILLIS_OF_SECOND;
                break;
        }
        return diff;
    }

    /**
     * get system current date
     */
    public static Date getSysDate() {
        return Calendar.getInstance().getTime();
    }

    /**
     * get system current timestamp
     *
     * @return time miliseconds
     */
    public static long getSysTimestamp() {
        return System.currentTimeMillis();
    }

    /**
     * date addition function
     *
     * @param date
     * @param field
     * @param amount
     * @return date object
     */
    public static Date add(Date date, int field, int amount) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(field, amount);
        return c.getTime();
    }

    public static Date addDays(Date date, int days) {
        return add(date, Calendar.DAY_OF_YEAR, days);
    }

    public static Date addMonths(Date date, int months) {
        return add(date, Calendar.MONTH, months);
    }

    public static Date addYears(Date date, int years) {
        return add(date, Calendar.YEAR, years);
    }

    public static Date addWeeks(Date date, int weeks) {
        return add(date, Calendar.WEEK_OF_YEAR, weeks);
    }

    public static Date addHours(Date date, int hours) {
        return add(date, Calendar.HOUR, hours);
    }

    public static Date addMinutes(Date date, int minutes) {
        return add(date, Calendar.MINUTE, minutes);
    }

    public static Date addSeconds(Date date, int seconds) {
        return add(date, Calendar.SECOND, seconds);
    }

    public static Date addMillisenconds(Date date, int millis) {
        return add(date, Calendar.MILLISECOND, millis);
    }

    public static String getTimestamp_YYMMDDhhmmsstnnp(int hours) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, hours);

        StringBuffer strBuf = new StringBuffer();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

        //
        strBuf.append(year.substring(2));

        if (month < 10) {
            strBuf.append("0");
        }
        strBuf.append(month);

        if (day < 10) {
            strBuf.append("0");
        }
        strBuf.append(day);

        if (hour < 10) {
            strBuf.append("0");
        }
        strBuf.append(hour);

        if (minute < 10) {
            strBuf.append("0");
        }
        strBuf.append(minute);

        if (second < 10) {
            strBuf.append("0");
        }
        strBuf.append(second);
        strBuf.append("0+32");

        return strBuf.toString();

    }

    public static String getTimestamp_YYMMDDhhmmsstnnp(int hours, String tnnp) {
        Calendar calendar = Calendar.getInstance();

        calendar.add(Calendar.HOUR_OF_DAY, hours);

        StringBuffer strBuf = new StringBuffer();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

        //
        strBuf.append(year.substring(2));

        if (month < 10) {
            strBuf.append("0");
        }
        strBuf.append(month);

        if (day < 10) {
            strBuf.append("0");
        }
        strBuf.append(day);

        if (hour < 10) {
            strBuf.append("0");
        }
        strBuf.append(hour);

        if (minute < 10) {
            strBuf.append("0");
        }
        strBuf.append(minute);

        if (second < 10) {
            strBuf.append("0");
        }
        strBuf.append(second);
        strBuf.append(tnnp);

        return strBuf.toString();

    }

    public static String getTimestamp_YYMMDDhhmmsstnnp() {
        Calendar calendar = Calendar.getInstance();

        StringBuffer strBuf = new StringBuffer();
        String year = String.valueOf(calendar.get(Calendar.YEAR));
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

        //
        strBuf.append(year.substring(2));

        if (month < 10) {
            strBuf.append("0");
        }
        strBuf.append(month);

        if (day < 10) {
            strBuf.append("0");
        }
        strBuf.append(day);

        if (hour < 10) {
            strBuf.append("0");
        }
        strBuf.append(hour);

        if (minute < 10) {
            strBuf.append("0");
        }
        strBuf.append(minute);

        if (second < 10) {
            strBuf.append("0");
        }
        strBuf.append(second);
        strBuf.append("0+32");

        return strBuf.toString();

    }

    public static String getTimestamp_YYYYMMDDhhmmss(int hours) {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, hours);

        StringBuffer strBuf = new StringBuffer();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

        //
        strBuf.append(year);

        if (month < 10) {
            strBuf.append("0");
        }
        strBuf.append(month);

        if (day < 10) {
            strBuf.append("0");
        }
        strBuf.append(day);

        if (hour < 10) {
            strBuf.append("0");
        }
        strBuf.append(hour);

        if (minute < 10) {
            strBuf.append("0");
        }
        strBuf.append(minute);

        if (second < 10) {
            strBuf.append("0");
        }
        strBuf.append(second);

        return strBuf.toString();

    }

    public static String getTimestamp_YYYYMMDDhhmmss() {
        Calendar calendar = Calendar.getInstance();
        //
        StringBuffer strBuf = new StringBuffer();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);

        //
        strBuf.append(year);

        if (month < 10) {
            strBuf.append("0");
        }
        strBuf.append(month);

        if (day < 10) {
            strBuf.append("0");
        }
        strBuf.append(day);

        if (hour < 10) {
            strBuf.append("0");
        }
        strBuf.append(hour);

        if (minute < 10) {
            strBuf.append("0");
        }
        strBuf.append(minute);

        if (second < 10) {
            strBuf.append("0");
        }
        strBuf.append(second);

        return strBuf.toString();
    }

    public static void main(String[] args) {
        System.out.println(now(DATETIME_FORMAT_S, TimeZone.getTimeZone("UTC")));
        System.out.println(now(DATETIME_FORMAT_S, TimeZone.getTimeZone("GMT")));
    }
}